package com.kly.pay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.exception.common.ApplicationException;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.androidpublisher.AndroidPublisher;
import com.google.api.services.androidpublisher.AndroidPublisherScopes;
import com.google.api.services.androidpublisher.model.ProductPurchase;
import com.kly.enums.*;
import com.kly.pay.db.dao.POrderDao;
import com.kly.pay.db.dao.POrderRepayDao;
import com.kly.pay.db.dao.PPayTaskDao;
import com.kly.pay.db.entity.POrderEntity;
import com.kly.pay.db.entity.POrderRepayEntity;
import com.kly.pay.db.entity.PPayTaskEntity;
import com.kly.pay.factory.GoogleApiService;
import com.kly.pay.factory.PayServiceFactory;
import com.kly.pay.service.BasicPayActionService;
import com.kly.pay.service.RetryTaskService;
import com.kly.req.RepayRequest;
import com.kly.req.RepayStatusRequest;
import com.kly.rsp.RepayResponse;
import com.kly.rsp.RepayStatusResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;

/**
 * googlePay支付处理类(一次性商品支付处理类)
 * @author linqu
 */
@Service
@Slf4j
public class GoogleOneTimeProductsPayImpl implements BasicPayActionService {

    @Resource
    POrderDao pOrderDao;
    @Resource
    POrderRepayDao pOrderRepayDao;
    @Resource
    PayServiceFactory payServiceFactory;
    @Resource
    RetryTaskService retryTaskService;


    /**
     * 返回支付网关：googlePay
     */
    @Override
    public PayGatewayEnum getPayType() {
        return PayGatewayEnum.GOOGLE_PAY;
    }

    private GoogleApiService getGoogleApiService(String packageName) {
        return payServiceFactory.buildGooglePayChannel(packageName);
    }
    /**
     * googlepay 调用到此接口时，已经通过SDK下单成功，需要调用消耗api(其实相当于二次确认），资金才会真正入账
     */
    @Override
    public RepayResponse repay(String payOrderNo, RepayRequest repayRequest) {
        log.info("[PaymentLog-onTimePurchase-repay] repay begin, userCode:{} orderNo:{} repayRequest:{}", repayRequest.getUserCode(), repayRequest.getOrderNo(), JSONObject.toJSONString(repayRequest));

        try {
            final String payExt = Optional.ofNullable(repayRequest.getPayExt()).orElse("");
            final JSONObject payExtJson = JSONObject.parseObject(payExt);

            final POrderEntity payOrder = pOrderDao.queryByPayOrderNo(payOrderNo);
            if (Objects.isNull(payOrder)) {
                log.error("[PaymentLog-onTimePurchase-repay] ThePayOrderNotExists, userCode:{} orderNo:{} payOrderNo:{}", repayRequest.getUserCode(), repayRequest.getOrderNo(), payOrderNo);
                throw new ApplicationException("ThePayOrderNotExists, payOrderNo:" + payOrderNo);
            }
            if (OrderStatus.PAID.getStatus() == payOrder.getStatus() || OrderStatus.CLOSE.getStatus() == payOrder.getStatus()) {
                log.info("[PaymentLog-onTimePurchase-repay] orderHasPaidOrClosed, userCode:{}, orderNo:{}", repayRequest.getUserCode(), repayRequest.getOrderNo());
                return RepayResponse.builder().payStatusEnum(PayStatusEnum.getEnumByCode(String.valueOf(payOrder.getStatus())))
                        .orderNo(payOrder.getOrderNo()).payOrderNo(payOrderNo).build();
            }

            ProductPurchase purchase = getProductPurchase(payOrderNo, repayRequest.getUserCode(), repayRequest.getOrderNo(), getGoogleApiService(payExtJson.getString("packageName")).getProducts(), payExtJson.getString("packageName"), payExtJson.getString("productId"), payExtJson.getString("purchaseToken"));

            PayStatusEnum payStatusEnum = PayStatusEnum.PROCESSING;
            final Integer purchaseState = purchase.getPurchaseState();
            final Integer consumptionState = purchase.getConsumptionState();

            // PurchaseState : 0. Purchased 1. Canceled 2. Pending
            if (purchaseState.equals(GooglePayPurchasesStatus.CANCELED.getStatus())) {
                log.info("[PaymentLog-onTimePurchase-repay] orderHasCanceled, userCode:{}, orderNo:{}", repayRequest.getUserCode(), repayRequest.getOrderNo());
                payStatusEnum = PayStatusEnum.CLOSED_ORDER;
                pOrderDao.updateOrderStatus(payOrderNo, PayTypeEnum.REPAY.getCode(), payStatusEnum.getCode());
                return RepayResponse.builder().payOrderNo(payOrderNo).payStatusEnum(payStatusEnum).build();
            }

            /**
             * PurchaseState : 0. Purchased 1. Canceled 2. Pending
             * ConsumptionState : 0. Yet to be consumed 1. Consumed
             */
            if (consumptionState.equals(GooglePayConsumerStatus.USED.getStatus())) {
                // 修改订单受理状态
                payStatusEnum = PayStatusEnum.PAY_SUCCESS;
                pOrderDao.repaySuccess(payOrderNo, payOrder.getPayType());
                // 插入入账成功记录表
                addRepayment(payOrderNo, payOrder);
                log.info("[PaymentLog-onTimePurchase-repay] orderHasPaidSuccess, userCode:{}, orderNo:{}", repayRequest.getUserCode(), repayRequest.getOrderNo());
                return RepayResponse.builder().payOrderNo(payOrderNo).payStatusEnum(payStatusEnum).build();
            }

            // 需要消耗商品
            if (consumptionState.equals(GooglePayConsumerStatus.UN_USED.getStatus())) {
                consume(repayRequest.getUserCode(), repayRequest.getOrderNo(), payExtJson.getString("packageName"), payExtJson.getString("productId"), payExtJson.getString("purchaseToken"));
                pOrderDao.updateOrderStatus(payOrderNo, PayTypeEnum.REPAY.getCode(), payStatusEnum.getCode());
                log.info("[PaymentLog-onTimePurchase-repay] orderHasPaidSuccess, userCode:{}, orderNo:{} repayRequest:{}", repayRequest.getUserCode(), repayRequest.getOrderNo(), JSONObject.toJSONString(repayRequest));

                // 添加重试任务
                retryTaskService.addTask(payOrderNo);

                return RepayResponse.builder().payOrderNo(payOrderNo).payStatusEnum(payStatusEnum).build();
            }
            log.error("[PaymentLog-onTimePurchase-repay] purchase paid, userCode:{}, orderNo:{} repayRequest:{}", repayRequest.getUserCode(), repayRequest.getOrderNo(), JSONObject.toJSONString(repayRequest));
        } catch (IOException e) {
            log.error("[PaymentLog-onTimePurchase-repay] purchase paid, userCode:{}, orderNo:{} repayRequest:{}", repayRequest.getUserCode(), repayRequest.getOrderNo(), JSONObject.toJSONString(repayRequest), e);

        }

        return null;
    }

    /**
     * 商品消耗
     */
    public void consume(String userCode, String orderNo, String packageName, String productId,String purchaseToken) {
        try{
            final AndroidPublisher.Purchases.Products.Consume consume
                    = getGoogleApiService(packageName).getProducts().consume(packageName, productId, purchaseToken);
            consume.execute();
            // TODO: 2023/7/17 通知api更改订单状态
            log.info("[PaymentLog-onTimePurchase-repay] AndroidPublisher.Purchases.Products.Consume.consume success, userCode:{}, orderNo:{}, packageName:{}, productId:{}, purchaseToken:{}", userCode, orderNo, packageName, productId, purchaseToken);
        } catch (Exception ex) {
            log.error("[PaymentLog-onTimePurchase-repay] AndroidPublisher.Purchases.Products.Consume.consume failed, userCode:{}, orderNo:{}, packageName:{}, productId:{}, purchaseToken:{}", userCode, orderNo, packageName, productId, purchaseToken, ex);
            throw new ApplicationException("AndroidPublisher.Purchases.Products.Consume.consume failed");
        }
    }

    /**
     * 调用googlePay api获取订单状态
     * packageName: 引号内包名
     * productId: 产品ID
     * purchaseToken: 访问googlePay的purchaseToken
     */
    private static ProductPurchase getProductPurchase(String payOrderNo, String userCode, String orderNo, AndroidPublisher.Purchases.Products products, String packageName, String productId, String purchaseToken) throws IOException {

        try {
            AndroidPublisher.Purchases.Products.Get product = products.get(
                    packageName,
                    productId,
                    purchaseToken);
            final ProductPurchase productPurchase = product.execute();
            log.info("[PaymentLog-onTimePurchase-repay] GetProductPurchaseSuccess, payOrderNo:{}, userCode:{}, orderNo:{} productPurchaseResult:{}", payOrderNo,  userCode, orderNo, JSONObject.toJSONString(productPurchase));
            return productPurchase;
        } catch (Exception e) {
            log.error("[PaymentLog-onTimePurchase-repay] AndroidPublisher.Purchases.Products.Get.execute failed, packageName:{}, productId:{}, purchaseToken:{}"
                    , packageName, productId, purchaseToken, e);
            throw new ApplicationException("AndroidPublisher.Purchases.Products.Get.execute failed");
        }
    }

    /**
     * 添加入账记录
     */
    private void addRepayment(String payOrderNo, POrderEntity payOrder) {
        final POrderRepayEntity repayOrder = pOrderRepayDao.queryByPayOrderNo(payOrderNo);
        if (Objects.nonNull(repayOrder)) {
            return;
        }
        POrderRepayEntity entity = new POrderRepayEntity();
        entity.setAmount(payOrder.getAmount());
        entity.setCreatedBy("admin");
//                entity.setMerchantCode()
        entity.setOrderNo(payOrder.getOrderNo());
        entity.setPayGateway(payOrder.getPayGateway());
        entity.setPayOrderNo(payOrderNo);
        entity.setProductCode(payOrder.getProductCode());
        entity.setRepayAccount(payOrder.getUserCode());
        pOrderRepayDao.insert(entity);
    }

    @Override
    public RepayStatusResponse repayStatusQuery(RepayStatusRequest repayStatusRequest) {
        log.error("[PaymentLog-onTimePurchase-repayStatusQuery] repayStatusQuery, userCode:{}, payOrderNo:{}, request:{}",repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo(), JSONObject.toJSONString(repayStatusRequest));

        final String payOrderNo = repayStatusRequest.getPayOrderNo();
        final String repayStatusExtReq = repayStatusRequest.getRepayStatusExtReq();
        final JSONObject repayStatusExtJson = JSONObject.parseObject(repayStatusExtReq);
        final String packageName = repayStatusExtJson.getString("packageName");
        final String productId = repayStatusExtJson.getString("productId");
        final String purchaseToken = repayStatusExtJson.getString("purchaseToken");
        final String orderId = repayStatusExtJson.getString("orderId");
        try {
            ProductPurchase purchase = getProductPurchase(payOrderNo, repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo(), getGoogleApiService(packageName).getProducts(), packageName, productId, purchaseToken);

            final POrderEntity payOrder = pOrderDao.queryByPayOrderNo(payOrderNo);
            if (Objects.isNull(payOrder)) {
                log.error("[PaymentLog-onTimePurchase-repayStatusQuery] ThePayOrderNotExists, userCode:{}, payOrderNo:{}, payOrderNo:{}",repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo(), payOrderNo);
                return null;
            }

            if (OrderStatus.PAID.getStatus() == payOrder.getStatus() || OrderStatus.CLOSE.getStatus() == payOrder.getStatus()) {
                log.info("[PaymentLog-onTimePurchase-repayStatusQuery] orderHasPaidOrClosed, userCode:{}, payOrderNo:{}, payOrderNo:{}", repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo(), payOrderNo);
                return RepayStatusResponse.builder().status(PayStatusEnum.getEnumByCode(String.valueOf(payOrder.getStatus())))
                        .orderNo(payOrder.getOrderNo()).payOrderNo(payOrderNo).build();
            }

            PayStatusEnum payStatusEnum = PayStatusEnum.PROCESSING;
            final Integer purchaseState = purchase.getPurchaseState();
            final Integer consumptionState = purchase.getConsumptionState();

            // PurchaseState : 0. Purchased 1. Canceled 2. Pending
            if (purchaseState.equals(GooglePayPurchasesStatus.CANCELED.getStatus())) {
                payStatusEnum = PayStatusEnum.CLOSED_ORDER;
                pOrderDao.updateOrderStatus(payOrderNo, PayTypeEnum.REPAY.getCode(), payStatusEnum.getCode());
                log.info("[PaymentLog-onTimePurchase-repayStatusQuery] order has canceled, userCode:{}, payOrderNo:{}, payOrderNo:{}", repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo(), payOrderNo);
                return RepayStatusResponse.builder().payOrderNo(payOrderNo).status(payStatusEnum).build();
            }

            /**
             * PurchaseState : 0. Purchased 1. Canceled 2. Pending
             * ConsumptionState : 0. Yet to be consumed 1. Consumed
             */
            if (consumptionState.equals(GooglePayConsumerStatus.USED.getStatus())) {
                // 修改订单受理状态
                payStatusEnum = PayStatusEnum.PAY_SUCCESS;
                pOrderDao.repaySuccess(payOrderNo, payOrder.getPayType());
                // 插入入账成功记录表
                addRepayment(payOrderNo, payOrder);
                log.info("[PaymentLog-onTimePurchase-repayStatusQuery] orderHasPaidSuccess, userCode:{}, orderNo:{}, payOrderNo:{}", repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo(), payOrderNo);
                return RepayStatusResponse.builder().payOrderNo(payOrderNo).status(payStatusEnum).build();
            }

            // 需要消耗商品
            if (consumptionState.equals(GooglePayConsumerStatus.UN_USED.getStatus())) {
                consume(repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo(), packageName, productId, purchaseToken);
                pOrderDao.updateOrderStatus(payOrderNo, PayTypeEnum.REPAY.getCode(), payStatusEnum.getCode());
                log.info("[PaymentLog-onTimePurchase-repayStatusQuery] orderHasConsumeOrClosed, userCode:{}, orderNo:{} repayRequest:{}", repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo(), payOrderNo);
                return RepayStatusResponse.builder().payOrderNo(payOrderNo).status(payStatusEnum).build();
            }

        } catch (IOException e) {
            log.error("[PaymentLog-onTimePurchase-repayStatusQuery] repayStatusQuery failed, userCode:{}, orderNo:{} repayRequest:{}", repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo(), payOrderNo, e);
        }

        return null;
    }

    @Override
    public String queryExtentInfo(RepayRequest repayRequest) {
        final String payExt = Optional.ofNullable(repayRequest.getPayExt()).orElse("");
        final JSONObject payExtJson = JSONObject.parseObject(payExt);
        try {
            ProductPurchase purchase = getProductPurchase("", "", "", getGoogleApiService(payExtJson.getString("packageName")).getProducts(), payExtJson.getString("packageName"), payExtJson.getString("productId"), payExtJson.getString("purchaseToken"));
            if (Objects.isNull(purchase)) {
                return null;
            }
            return JSONObject.toJSONString(purchase);
        } catch (Exception e) {
            log.error("[PaymentLog-onTimePurchase-queryExtentInfo] QueryExtentInfoFailed, params:{}", JSONObject.toJSONString(repayRequest), e);
        }
        return null;
    }


    public static void main(String[] args) throws Exception {

        String googlePayCredential = "{\n" +
                "  \"type\": \"service_account\",\n" +
                "  \"project_id\": \"passionpulse-6112f\",\n" +
                "  \"private_key_id\": \"5e34cb79703e755e5bdbfadc90c68f9e3a8ac01b\",\n" +
                "  \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5VHxMNOGDqucB\\nml7eCRYOcKtG6w3KUz9Kw2iT7FEhuKu+f2YgKDMWz6ubZxC1+yCp40oY8HdQiLrU\\niE2jmEl2782C9+6HAbfSmDmYwsc7bGTkzBVnj5QCpfrSb0syWflwueCds1vppzup\\nCqukzbxOG7yIEA8rhAriEtm8y13in7/lhFBAC2UZguUWH0Ok1OizU9/pp0JbtIQZ\\n3+fanaCp+WbxbFMxwi+Aj7eZFzA5GRwslxyzQ6A1CtGdpq1tKVxinWq69/690O7g\\nMTp8NZd78x4dtRV0Gzrz7baCVRjnRWA3/q1b5D9dRFrTYFuJL+t3Agn5fWLqdp/C\\nRi+53A/3AgMBAAECggEAQPNS/IIr5rEmdHFdfgNBL55c6GXIV3gFXnZNWEohxOer\\niP+tEugDv6LYSYY9XQm90MxPU54yso64q3N5gjQEyyIPrC6n8biwa6XdyaO5nyHF\\n2kmL1teCz8rLtKQ8flD6En+SMLKDK8foKL4MmZ1guR8PW8AFEQMdrU1d8cR0Cs/I\\n9HjdZEWUQffwNO/oyMQyYLFOE70o4JbcOV5fYUmemyMa7KJmu5K40EIEzu0gwWde\\nVhbSYcCgfNX4T4jc9BEb3jwv/9L5cJ1SwvJKVSWmUEIhAiC2TT53Ek8PlQok4lCA\\njzzQ5KYhbyYJAsYFHm/DvGSOnt8gxi0t5gWndDfMAQKBgQDhjovWyE/Xkk4dJ6q9\\nw6z6Jd6sEtY5iWq+HnO6FI4YCHJeBirnuKgrKkMZ6HhP1DDr7KihzRCCrD6OAip4\\nmGOI4HihkMT4xJqXCg6Embklng4/Mfu5PstLS8pm1cDFOGr4aa44otgZbuMgvnGn\\nVpE/eKK9DOSS9mNBnnus23ZNtwKBgQDSWAU0ZRBBj/yrnGt0Cdmbkn/Tv91Jwq/R\\nCU3DqwgiTYM45N2Dv8uW/Ae44CAVdxiFKmJ7VrIQoiOAcotQmLIIH+FlEvuMCp0d\\nm2gzy6jPyJP7UVsa9dxqhWInPExY5Or1aChUP+Ew1wYYi7bi3zGYgj9vIFbVEOZK\\n7uAHWdBPwQKBgQCwQwLIb3TlUzGz2uG0tYshWCKweW/rOpWtyIJLMfDwmvk0vMEe\\nn9DbGoWhY2dRitJIK4KEHon+c7fWpZ6m6v8tYa0jJMyoUosz6On7eV2UJfWgMOEz\\nm/yl9K5Quk2QUUxWn89D9w3EokDfv7N1P1L2NMGH1uFwbxaVmtGu/Tlv9QKBgQCF\\nKSX6WnSlHNNXjQnVhxrUyzTTR6Z+uJp3Wk15rr/Sf4GwNesqKfRoHBuDZZfKHwBN\\n5Vw9OtA1iX+yJFGf71rdm9kkFJVcvadjg+u+xpKTICbWtlVXxwgIA3L05c5rhFhe\\njdbiJyKXubhpN6HLFIMgSmyAHFf8QNuZ2onG/YvLwQKBgBhfi3RMDUDqxpB08Qz5\\nmIeoFB/Mew+rNRx9Ntf7QDC6cAyiYaxhZzc3tKFCipJz1tfNa8/expTx9VJR8eXa\\nJj/x/CQNxrkoSkV5fIZYFOBf4GI9l0wjIoA8DUp0xhXi+yK1Got6y6fmPNgRNf0z\\naNCgh9IKFLjlUa3WenSYxJYL\\n-----END PRIVATE KEY-----\\n\",\n" +
                "  \"client_email\": \"pp-pay@passionpulse-6112f.iam.gserviceaccount.com\",\n" +
                "  \"client_id\": \"106399706746116188334\",\n" +
                "  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n" +
                "  \"token_uri\": \"https://oauth2.googleapis.com/token\",\n" +
                "  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n" +
                "  \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/pp-pay%40passionpulse-6112f.iam.gserviceaccount.com\",\n" +
                "  \"universe_domain\": \"googleapis.com\"\n" +
                "}";

//        System.out.println(googlePayCredential);

        GoogleCredential credential = GoogleCredential.fromStream(new ByteArrayInputStream(googlePayCredential.getBytes()))
                .createScoped(AndroidPublisherScopes.all());
        //credential.refreshToken();//注意这里
        if(credential==null) {
            log.error("==========>Get GoogleCredential fails 获取谷歌凭证失败！");
        }
        HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        JacksonFactory jacksonFactory = JacksonFactory.getDefaultInstance();
        AndroidPublisher publisher = new AndroidPublisher.Builder(httpTransport, jacksonFactory, credential).build();


        final AndroidPublisher.Purchases.Products products = publisher.purchases().products();
        ProductPurchase purchase = getProductPurchase("", "", "", products, "com.kky.pp", "pppv1", "ookpolokalibahbpidhialmb.AO-J1OwDfXsHs5A10EL7pDCXZxd74v3LN-jsvlPYMQQ3udEEzoQdB1JapGPKm3J8eElI8NS7UvjWY8hTtdNCAICK3HgpzNPKjA");
        System.out.println(JSONObject.toJSONString(purchase));



    }
}
